/**
 *
 */
package cn.xiaolang.thread.future_callable;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Future模式的多线程
 * <p>
 * Future模式的核心在于：去除了主函数的等待时间，并使得原本需要等待的时间段可以用于处理其他业务逻辑
 * Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。
 * 必要时可以通过get方法获取执行结果，该方法会阻塞直到任务返回结果。
 * </p>
 *
 * <p>
 * 适用场景：
 * </p>
 * <p>
 * 在并发编程时，一般使用runnable，然后扔给线程池完事，这种情况下不需要线程的结果。 所以run的返回值是void类型。
 * 如果是一个多线程协作程序，比如菲波拉切数列，1，1，2，3，5，8...使用多线程来计算。 但后者需要前者的结果，就需要用callable接口了。
 * callable用法和runnable一样，只不过调用的是call方法，该方法有一个泛型返回值类型，你可以任意指定。
 * 线程是属于异步计算模型，所以你不可能直接从别的线程中得到函数返回值。
 * 这时候，Future就出场了。Futrue可以监视目标线程调用call的情况，当你调用Future的get()方法以获得结果时，当前线程就开始阻塞，直接call方法结束返回结果
 * </p>
 *
 *
 *
 * @author fuhw
 * @date 2017年8月25日 上午11:43:04
 */
public class FutureAndCallableDemo {

    private static final AtomicInteger count = new AtomicInteger(0);

    /**
     * Client主要完成的功能包括：
     * 		1. 返回一个FutureData；
     * 		2.开启一个线程用于构造RealData。
     */
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(3);
        List<Future<String>> futures = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            futures.add(service.submit(new CallableWork(i)));
        }
        futures.forEach(temp -> {
            try {
                System.out.println(temp.get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
                Thread.currentThread().interrupt();
            }
        });
        futures.clear();
        service.shutdown();
    }

    public static class CallableWork implements Callable<String> {

        private final int taskNo;

        public CallableWork(int i) {
            this.taskNo = i;
        }

        @Override
        public String call() throws Exception {
            return "任务编码：" + taskNo + "," + Thread.currentThread().getName() + "=>" + ",计数器值:"
                    + count.incrementAndGet();
        }
    }
}
